import React, { Component, ErrorInfo, ReactNode } from 'react';
import { Result, Button, Typography, Collapse, Space } from 'antd';
import { 
  BugOutlined, 
  ReloadOutlined, 
  HomeOutlined,
  WarningOutlined,
  InfoCircleOutlined
} from '@ant-design/icons';
import classNames from 'classnames';
import styles from './ErrorBoundary.module.css';

const { Text, Paragraph } = Typography;
const { Panel } = Collapse;

/**
 * 错误信息接口
 */
export interface IErrorInfo {
  /** 错误对象 */
  error: Error;
  /** 错误信息 */
  errorInfo: ErrorInfo;
  /** 错误发生时间 */
  timestamp: number;
  /** 用户代理信息 */
  userAgent: string;
  /** 页面URL */
  url: string;
}

/**
 * 错误边界组件属性接口
 */
export interface IErrorBoundaryProps {
  /** 子组件 */
  children: ReactNode;
  /** 自定义错误页面 */
  fallback?: (errorInfo: IErrorInfo) => ReactNode;
  /** 错误发生时的回调 */
  onError?: (errorInfo: IErrorInfo) => void;
  /** 是否显示错误详情 */
  showErrorDetails?: boolean;
  /** 是否显示重试按钮 */
  showRetryButton?: boolean;
  /** 是否显示返回首页按钮 */
  showHomeButton?: boolean;
  /** 是否启用错误上报 */
  enableErrorReporting?: boolean;
  /** 错误上报函数 */
  reportError?: (errorInfo: IErrorInfo) => void;
  /** 自定义类名 */
  className?: string;
  /** 自定义样式 */
  style?: React.CSSProperties;
}

/**
 * 错误边界组件状态接口
 */
interface IErrorBoundaryState {
  /** 是否有错误 */
  hasError: boolean;
  /** 错误信息 */
  errorInfo: IErrorInfo | null;
  /** 错误ID */
  errorId: string | null;
}

/**
 * 错误边界组件
 * @description React错误边界组件，用于捕获和处理组件树中的JavaScript错误
 */
class ErrorBoundary extends Component<IErrorBoundaryProps, IErrorBoundaryState> {
  constructor(props: IErrorBoundaryProps) {
    super(props);
    this.state = {
      hasError: false,
      errorInfo: null,
      errorId: null
    };
  }

  /**
   * 捕获错误并更新状态
   */
  static getDerivedStateFromError(error: Error): Partial<IErrorBoundaryState> {
    return {
      hasError: true,
      errorId: `error_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
    };
  }

  /**
   * 处理错误信息
   */
  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    const errorData: IErrorInfo = {
      error,
      errorInfo,
      timestamp: Date.now(),
      userAgent: navigator.userAgent,
      url: window.location.href
    };

    this.setState({
      errorInfo: errorData
    });

    // 调用错误回调
    if (this.props.onError) {
      this.props.onError(errorData);
    }

    // 错误上报
    if (this.props.enableErrorReporting && this.props.reportError) {
      this.props.reportError(errorData);
    }

    // 控制台输出错误信息
    console.error('ErrorBoundary caught an error:', error, errorInfo);
  }

  /**
   * 重试操作
   */
  handleRetry = () => {
    this.setState({
      hasError: false,
      errorInfo: null,
      errorId: null
    });
  };

  /**
   * 返回首页
   */
  handleGoHome = () => {
    window.location.href = '/';
  };

  /**
   * 复制错误信息
   */
  handleCopyError = () => {
    if (!this.state.errorInfo) return;

    const errorText = this.formatErrorForCopy(this.state.errorInfo);
    
    if (navigator.clipboard) {
      navigator.clipboard.writeText(errorText).then(() => {
        // 可以添加复制成功的提示
        console.log('错误信息已复制到剪贴板');
      });
    } else {
      // 降级方案
      const textArea = document.createElement('textarea');
      textArea.value = errorText;
      document.body.appendChild(textArea);
      textArea.select();
      document.execCommand('copy');
      document.body.removeChild(textArea);
      console.log('错误信息已复制到剪贴板');
    }
  };

  /**
   * 格式化错误信息用于复制
   */
  formatErrorForCopy = (errorInfo: IErrorInfo): string => {
    return `
错误报告
========
错误ID: ${this.state.errorId}
时间: ${new Date(errorInfo.timestamp).toLocaleString()}
URL: ${errorInfo.url}
用户代理: ${errorInfo.userAgent}

错误信息:
${errorInfo.error.name}: ${errorInfo.error.message}

错误堆栈:
${errorInfo.error.stack}

组件堆栈:
${errorInfo.errorInfo.componentStack}
    `.trim();
  };

  /**
   * 渲染错误详情
   */
  renderErrorDetails = () => {
    const { showErrorDetails = true } = this.props;
    const { errorInfo, errorId } = this.state;

    if (!showErrorDetails || !errorInfo) {
      return null;
    }

    return (
      <div className={styles.errorDetails}>
        <Collapse ghost>
          <Panel
            header={
              <Space>
                <InfoCircleOutlined />
                <Text>错误详情</Text>
              </Space>
            }
            key="details"
          >
            <div className={styles.errorContent}>
              <div className={styles.errorItem}>
                <Text strong>错误ID:</Text>
                <Text code>{errorId}</Text>
              </div>
              
              <div className={styles.errorItem}>
                <Text strong>错误类型:</Text>
                <Text code>{errorInfo.error.name}</Text>
              </div>
              
              <div className={styles.errorItem}>
                <Text strong>错误信息:</Text>
                <Paragraph code copyable>
                  {errorInfo.error.message}
                </Paragraph>
              </div>
              
              <div className={styles.errorItem}>
                <Text strong>发生时间:</Text>
                <Text>{new Date(errorInfo.timestamp).toLocaleString()}</Text>
              </div>
              
              <div className={styles.errorItem}>
                <Text strong>页面地址:</Text>
                <Text code>{errorInfo.url}</Text>
              </div>
              
              {errorInfo.error.stack && (
                <div className={styles.errorItem}>
                  <Text strong>错误堆栈:</Text>
                  <Paragraph code className={styles.stackTrace}>
                    {errorInfo.error.stack}
                  </Paragraph>
                </div>
              )}
              
              {errorInfo.errorInfo.componentStack && (
                <div className={styles.errorItem}>
                  <Text strong>组件堆栈:</Text>
                  <Paragraph code className={styles.stackTrace}>
                    {errorInfo.errorInfo.componentStack}
                  </Paragraph>
                </div>
              )}
            </div>
          </Panel>
        </Collapse>
      </div>
    );
  };

  /**
   * 渲染操作按钮
   */
  renderActions = () => {
    const { showRetryButton = true, showHomeButton = true } = this.props;

    const actions = [];

    if (showRetryButton) {
      actions.push(
        <Button
          key="retry"
          type="primary"
          icon={<ReloadOutlined />}
          onClick={this.handleRetry}
        >
          重新加载
        </Button>
      );
    }

    if (showHomeButton) {
      actions.push(
        <Button
          key="home"
          icon={<HomeOutlined />}
          onClick={this.handleGoHome}
        >
          返回首页
        </Button>
      );
    }

    actions.push(
      <Button
        key="copy"
        icon={<InfoCircleOutlined />}
        onClick={this.handleCopyError}
      >
        复制错误信息
      </Button>
    );

    return actions;
  };

  /**
   * 渲染默认错误页面
   */
  renderDefaultErrorPage = () => {
    const { className, style } = this.props;

    const errorClassName = classNames(
      styles.errorBoundary,
      className
    );

    return (
      <div className={errorClassName} style={style}>
        <Result
          status="error"
          icon={<BugOutlined />}
          title="页面出现了错误"
          subTitle="抱歉，页面遇到了一个意外错误。您可以尝试刷新页面或返回首页。"
          extra={this.renderActions()}
        />
        {this.renderErrorDetails()}
      </div>
    );
  };

  render() {
    const { hasError, errorInfo } = this.state;
    const { children, fallback } = this.props;

    if (hasError && errorInfo) {
      // 如果提供了自定义错误页面，使用自定义页面
      if (fallback) {
        return fallback(errorInfo);
      }

      // 否则使用默认错误页面
      return this.renderDefaultErrorPage();
    }

    // 正常渲染子组件
    return children;
  }
}

export default ErrorBoundary;